package com.coursehub.shared.transaction;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 分布式事务管理器
 * 基于Saga模式实现分布式事务协调
 */
@Slf4j
@Component
public class DistributedTransactionManager {
    
    private final ConcurrentMap<String, TransactionContext> transactions = new ConcurrentHashMap<>();
    
    /**
     * 开始分布式事务
     */
    public String beginTransaction(String transactionName) {
        String transactionId = UUID.randomUUID().toString();
        TransactionContext context = new TransactionContext(transactionId, transactionName);
        transactions.put(transactionId, context);
        
        log.info("开始分布式事务: {} [{}]", transactionName, transactionId);
        return transactionId;
    }
    
    /**
     * 添加事务步骤
     */
    public void addStep(String transactionId, TransactionStep step) {
        TransactionContext context = transactions.get(transactionId);
        if (context == null) {
            throw new IllegalArgumentException("事务不存在: " + transactionId);
        }
        
        context.addStep(step);
        log.debug("添加事务步骤: {} -> {}", transactionId, step.getStepName());
    }
    
    /**
     * 执行分布式事务
     */
    public CompletableFuture<TransactionResult> executeTransaction(String transactionId) {
        TransactionContext context = transactions.get(transactionId);
        if (context == null) {
            return CompletableFuture.completedFuture(
                TransactionResult.failure("事务不存在: " + transactionId)
            );
        }
        
        return CompletableFuture.supplyAsync(() -> {
            try {
                return executeSteps(context);
            } catch (Exception e) {
                log.error("执行分布式事务失败: {}", transactionId, e);
                return TransactionResult.failure("事务执行失败: " + e.getMessage());
            } finally {
                transactions.remove(transactionId);
            }
        });
    }
    
    /**
     * 执行事务步骤
     */
    private TransactionResult executeSteps(TransactionContext context) {
        List<TransactionStep> executedSteps = new ArrayList<>();
        
        try {
            // 正向执行所有步骤
            for (TransactionStep step : context.getSteps()) {
                log.debug("执行事务步骤: {} -> {}", context.getTransactionId(), step.getStepName());
                step.execute();
                executedSteps.add(step);
            }
            
            log.info("分布式事务执行成功: {} [{}]", context.getTransactionName(), context.getTransactionId());
            return TransactionResult.success("事务执行成功");
            
        } catch (Exception e) {
            log.error("事务步骤执行失败，开始补偿: {} [{}]", context.getTransactionName(), context.getTransactionId(), e);
            
            // 反向补偿已执行的步骤
            compensateSteps(executedSteps, context.getTransactionId());
            
            return TransactionResult.failure("事务执行失败: " + e.getMessage());
        }
    }
    
    /**
     * 补偿已执行的步骤
     */
    private void compensateSteps(List<TransactionStep> executedSteps, String transactionId) {
        // 反向补偿
        for (int i = executedSteps.size() - 1; i >= 0; i--) {
            TransactionStep step = executedSteps.get(i);
            try {
                log.debug("补偿事务步骤: {} -> {}", transactionId, step.getStepName());
                step.compensate();
            } catch (Exception compensateException) {
                log.error("补偿步骤失败: {} -> {}", transactionId, step.getStepName(), compensateException);
                // 补偿失败，记录日志但继续补偿其他步骤
            }
        }
        
        log.info("事务补偿完成: {}", transactionId);
    }
    
    /**
     * 获取事务状态
     */
    public TransactionStatus getTransactionStatus(String transactionId) {
        TransactionContext context = transactions.get(transactionId);
        if (context == null) {
            return TransactionStatus.NOT_FOUND;
        }
        return context.getStatus();
    }
    
    /**
     * 取消事务
     */
    public void cancelTransaction(String transactionId) {
        TransactionContext context = transactions.remove(transactionId);
        if (context != null) {
            log.info("取消分布式事务: {} [{}]", context.getTransactionName(), transactionId);
        }
    }
}